package cn.edu.sgu.www.pms.service.impl;

import cn.edu.sgu.www.pms.consts.CustomMessages;
import cn.edu.sgu.www.pms.dto.UserDTO;
import cn.edu.sgu.www.pms.dto.UserRegisterDTO;
import cn.edu.sgu.www.pms.entity.User;
import cn.edu.sgu.www.pms.enums.LockStatus;
import cn.edu.sgu.www.pms.exception.GlobalException;
import cn.edu.sgu.www.pms.mapper.ApplicationMapper;
import cn.edu.sgu.www.pms.mapper.UserMapper;
import cn.edu.sgu.www.pms.restful.ResponseCode;
import cn.edu.sgu.www.pms.service.UserService;
import cn.edu.sgu.www.pms.util.ObjectUtils;
import cn.edu.sgu.www.pms.util.PasswordEncoder;
import cn.edu.sgu.www.pms.util.StringUtils;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.List;

/**
 * @author 沐雨橙风ιε
 * @version 1.0
 */
@Slf4j
@Service
public class UserServiceImpl implements UserService {

    private final UserMapper userMapper;
    private final ApplicationMapper applicationMapper;

    @Autowired
    public UserServiceImpl(UserMapper userMapper, ApplicationMapper applicationMapper) {
        this.userMapper = userMapper;
        this.applicationMapper = applicationMapper;
    }

    @Override
    public void lock(String userId) {
        UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();

        updateWrapper.eq("id", userId);
        updateWrapper.set("lock_status", LockStatus.LOCK.getValue());

        userMapper.update(updateWrapper.getEntity(), updateWrapper);
    }

    @Override
    public void login(String username, String password) {
        Subject subject = SecurityUtils.getSubject();

        if (!subject.isAuthenticated()) {
            UsernamePasswordToken token = new UsernamePasswordToken(username, password);

            subject.login(token);
        }
    }

    @Override
    public void register(UserRegisterDTO registerDTO) {
        // 获取注册的用户名
        String username = registerDTO.getUsername();
        // 得到应用ID
        Integer serviceId = applicationMapper.getServiceId(registerDTO.getService());

        // 判断用户名是否已被注册
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();

        queryWrapper.eq("username", username);
        queryWrapper.eq("service_id", serviceId);

        User user = userMapper.selectOne(queryWrapper);

        // 查询结果不为null，则用户名已经被注册过了，注册失败
        if (user != null) {
            throw new GlobalException(ResponseCode.CONFLICT, "用户名已存在，注册失败~");
        }

        user = new User();

        user.setGender(0);
        user.setUsername(username);
        user.setServiceId(serviceId);
        user.setId(StringUtils.uuid());
        user.setName(registerDTO.getName());
        user.setPhone(registerDTO.getPhone());
        user.setLockStatus(LockStatus.UN_LOCK.getValue());

        // 保存加密后的密码
        String password = registerDTO.getPassword();

        user.setPassword(PasswordEncoder.encode(password));

        userMapper.insert(user);
    }

    @Override
    public void logout() {
        Subject subject = SecurityUtils.getSubject();

        if (subject.isAuthenticated()) {
            Object principal = subject.getPrincipal();
            User user = (User) principal;

            log.debug("用户{}退出登录了...", user.getUsername());

            subject.logout();
        }
    }

    @Override
    public void insert(UserDTO userDTO) {
        User user = toEntity(userDTO);

        // 设置默认的密码
        String password = PasswordEncoder.encode("12345");

        user.setPassword(password);

        userMapper.insert(user);
    }

    @Override
    public void deleteByIds(List<String> ids) {
        userMapper.deleteBatchIds(ids);
    }

    @Override
    public void updateById(UserDTO userDTO) {
        ObjectUtils.requireNonNull(userDTO.getId(), CustomMessages.ID_NOT_NULL);

        User user = toEntity(userDTO);

        user.setLastLoginTime(LocalDateTime.now());

        userMapper.updateById(user);
    }

    @Override
    public User selectById(String id) {
        return userMapper.selectById(id);
    }

    @Override
    public List<User> selectList() {
        return userMapper.selectList(null);
    }

    @Override
    public User selectByUsername(String username, String service) {
        Integer serviceId = applicationMapper.getServiceId(service);

        if (serviceId == null) {
            throw new GlobalException(ResponseCode.NOT_FOUND, "查询应用失败，应用" + service + "不存在！");
        }

        // 通过用户名和应用ID查询用户信息
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();

        queryWrapper.eq("username", username);
        queryWrapper.eq("service_id", serviceId);

        return userMapper.selectOne(queryWrapper);
    }

    @Override
    public void updateByUsername(User user, String service) {
        Integer serviceId = applicationMapper.getServiceId(service);

        if (serviceId == null) {
            throw new GlobalException(ResponseCode.NOT_FOUND, "查询应用失败，应用" + service + "不存在！");
        }

        QueryWrapper<User> queryWrapper = new QueryWrapper<>();

        queryWrapper.eq("username", user.getUsername());
        queryWrapper.eq("service_id", serviceId);

        User result = userMapper.selectOne(queryWrapper);

        if (result == null) {
            throw new GlobalException(ResponseCode.NOT_FOUND, "修改失败，用户不存在！");
        }

        user.setId(result.getId());

        userMapper.updateById(user);
    }

    @Override
    public void updateLastLoginTime(String userId, LocalDateTime lastLoginTime) {
        UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();

        updateWrapper.eq("id", userId);
        updateWrapper.set("last_login_time", lastLoginTime);

        userMapper.update(updateWrapper.getEntity(), updateWrapper);
    }

    /**
     * DTO转换位数据库实体类
     * @param userDTO UserDTO
     * @return User
     */
    private User toEntity(UserDTO userDTO) {
        User user = new User();

        user.setId(userDTO.getId());
        user.setName(userDTO.getName());
        user.setPhone(userDTO.getPhone());
        user.setGender(userDTO.getGender());
        user.setUsername(userDTO.getUsername());
        user.setServiceId(userDTO.getServiceId());
        user.setLockStatus(userDTO.getLockStatus());

        return user;
    }

}